package cn.com.open.itembank.logic.importfilereader;

import cn.com.open.itembank.common.CommonFunction;
import cn.com.open.itembank.common.enums.ImportType;
import cn.com.open.itembank.common.enums.ResourceFileType;
import cn.com.open.itembank.dto.QuestionImportModel;
import cn.com.open.itembank.dto.ResourceResponse;
import cn.com.open.itembank.util.FileUtils;
import org.apache.poi.POIXMLDocument;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.extractor.WordExtractor;
import org.apache.poi.hwpf.model.ListData;
import org.apache.poi.hwpf.model.ListTables;
import org.apache.poi.hwpf.model.PicturesTable;
import org.apache.poi.hwpf.model.SEPX;
import org.apache.poi.hwpf.usermodel.*;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.usermodel.*;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * Created by lucky on 2017/12/15.
 */
public class WordFileReader implements FileReader {

    private static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(WordFileReader.class);

    private String appkey = "";
    private String appSecret = "";
    private String resourceApiUrl = "";
    private int imageSaveType = 0;

    private String subItemQuestionTypeSeparator = "\\[子题型]";
    private String subItemSeparator = "\\[子题]";
    private String questionTypeSeparator = "\\[题型]";

    private String answerPattern = "([A-Z]{1}[\\.]+)";

    /**
     * 得到文件类型.
     *
     * @return the import type
     */
    @Override
    public ImportType getImportType() {
        return ImportType.WORD;
    }

    public WordFileReader() {
    }

    /**
     * Instantiates a new Word file reader.
     *
     * @param appKey         the app key
     * @param appSecret      the app secret
     * @param resourceApiUrl 资源服务路径
     * @param imageSaveType  图片保存方式
     */
    public WordFileReader(String appKey, String appSecret, String resourceApiUrl, int imageSaveType) {
        this.appkey = appKey;
        this.appSecret = appSecret;
        this.resourceApiUrl = resourceApiUrl;
        this.imageSaveType = imageSaveType;
    }

    /**
     * 得到数据模型.
     *         ||

     * @param filePath the file path
     */
    @Override
    public List<QuestionImportModel> getDataList(String filePath,String extendName) {
        String content = null;
        if(".docx".equalsIgnoreCase(extendName)){
            content = getDataWordList(filePath);
        }else if(".doc".equalsIgnoreCase(extendName)){
            try {
                content = getDataStr(filePath);
            } catch (Exception e) {
                logger.error(e);
            }
        }
        return fillData(content);
    }

    //region 读取word数据

    /**
     * 读取word数.
     *
     * @param filePath the file path
     * @return the data word list
     */
    private String getDataWordList(String filePath) {
        StringBuilder sbWord = new StringBuilder();

        try (OPCPackage opcPackage = POIXMLDocument.openPackage(filePath); XWPFDocument xwpfd = new XWPFDocument(opcPackage)) {
            for (IBodyElement element : xwpfd.getBodyElements()) {
                if (element.getElementType() == BodyElementType.PARAGRAPH) {
                    XWPFParagraph paragraph = (XWPFParagraph) element;

                    for (XWPFRun run : paragraph.getRuns()) {
                        if (run.getText(run.getTextPosition()) != null) {
                            sbWord.append(run.getText(run.getTextPosition()));
                        }
                        for (XWPFPicture xwpfPicture : run.getEmbeddedPictures()) {
                            XWPFPictureData data = xwpfPicture.getPictureData();
                            if (data != null) {

                                //获取到图片名（*.jpg）
                                String resourceId = uploadPicture(data);

                                if (!resourceId.isEmpty()) {
                                    sbWord.append(getPitureData(resourceId));
                                } else {
                                    String errorMsg = String.format("图片上传错误，文件名: %s", data.getFileName());
                                    logger.error(errorMsg);
                                    sbWord.append(errorMsg);
                                }
                            }
                        }
                    }
                }

                if (element.getElementType() == BodyElementType.TABLE) {
                    sbWord.append("<table>");
                    XWPFTable table = (XWPFTable) element;
                    for (XWPFTableRow row : table.getRows()) {
                        sbWord.append("<tr>");
                        for (XWPFTableCell cell : row.getTableCells()) {
                            sbWord.append("<td>");
                            sbWord.append(cell.getText());
                            sbWord.append("</td>");
                        }
                        sbWord.append("</tr>");
                    }
                    sbWord.append("</table>");
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
        }

        return sbWord.toString();
    }

    //endregion

    //region 得到试题模型

    /**
     * 得到试题模型.
     *
     * @param itemString the item string
     * @return the question import model
     */
    private QuestionImportModel makeItem(String itemString) {
        QuestionImportModel itemModel = new QuestionImportModel();

        String[] itemWithoutSub = itemString.split("(\\[章节]|\\[类别]|\\[题干]|\\[选项]|\\[答案]|\\[解析]|\\[难度]|\\[分数]|\\[是否客观])");

        itemModel.setQuestionTypeName(removeNewLine(itemWithoutSub[0]));
        if (itemWithoutSub.length >= 9) {
            itemModel.setChapter(removeNewLine(itemWithoutSub[1]));
            itemModel.setQuestionCategoryName(removeNewLine(itemWithoutSub[2]));
            itemModel.setPrompt(convertNewLineString(itemWithoutSub[3]));

            itemModel.getChoices().addAll(CommonFunction.getListRemoveEmptyEntities(removeNewLine(itemWithoutSub[4]), answerPattern));
            itemModel.getAnswer().addAll(CommonFunction.getList(removeNewLine(itemWithoutSub[5]), CommonFunction.SEPARATOR));

            itemModel.setQuestionAnalysis(convertNewLineString(itemWithoutSub[6]));
            itemModel.setSaveDiffWord(removeNewLine(itemWithoutSub[7]));
            itemModel.setScore(removeNewLine(itemWithoutSub[8]));
            itemModel.setIsObjective(removeNewLine(itemWithoutSub.length > 9 ? itemWithoutSub[9].trim() : "是"));
        }

        return itemModel;
    }
    //endregion

    //region 得到子试题模型

    /**
     * 得到子试题模型.
     *
     * @param subItemString the sub item string
     * @param item          the item
     * @return the question import model
     */
    private QuestionImportModel makeSubItem(String subItemString, QuestionImportModel item) {
        QuestionImportModel subItemModel = new QuestionImportModel();

        String[] subItemInfo = subItemString.split("(\\[题干]|\\[选项]|\\[答案]|\\[解析]|\\[分数])", -1);

        subItemModel.setQuestionTypeName(removeNewLine(subItemInfo[0]));
        if (subItemInfo.length >= 6) {
            subItemModel.setPrompt(convertNewLineString(subItemInfo[1]));

            if (subItemInfo[2].trim().length() > 0) {
                subItemModel.getChoices().addAll(CommonFunction.getListRemoveEmptyEntities(removeNewLine(subItemInfo[2]), answerPattern));
            }
            subItemModel.getAnswer().addAll(CommonFunction.getList(removeNewLine(subItemInfo[3]), CommonFunction.SEPARATOR));
            subItemModel.setQuestionAnalysis(convertNewLineString(subItemInfo[4]));
            subItemModel.setScore(removeNewLine(subItemInfo[5]));
        }

        subItemModel.setChapter(item.getChapter().trim());
        subItemModel.setQuestionCategoryName(item.getQuestionCategory().trim());
        subItemModel.setSaveDiffWord(item.getSaveDiffWord().trim());

        return subItemModel;
    }
    //endregion

    //region 填充数据

    /**
     * 填充数据
     *
     * @param content the content
     * @return the list
     */
    public List<QuestionImportModel> fillData(String content) {
        List<QuestionImportModel> list = new ArrayList<>();

        for (String item : content.split(questionTypeSeparator)) {
            if (item.trim().length() == 0) {
                continue;
            }

            String[] itemWithSub = item.split(subItemSeparator);

            QuestionImportModel itemModel = makeItem(itemWithSub[0]);

            List<QuestionImportModel> subItemModelList = new ArrayList<>();

            //子题部分首先按子题型截取
            if (itemWithSub.length > 1) {
                List<String> subItemList = CommonFunction.getListRemoveEmptyEntities(itemWithSub[1].trim(), subItemQuestionTypeSeparator);

                for (String subItem : subItemList) {
                    QuestionImportModel subItemModel = makeSubItem(subItem, itemModel);
                    subItemModelList.add(subItemModel);
                }

                itemModel.getSubItems().addAll(subItemModelList);
            }

            itemModel.check();
            list.add(itemModel);
        }

        return list;
    }
    //endregion

    //region 图片处理部分

    /**
     * 根据资源id得到插入的图片信息html.
     *
     * @param resourceId 资源id
     * @return 图片信息html
     * @throws IOException the io exception
     */
    public String getPitureData(String resourceId) throws IOException {
        String formatTag = "<img src=\"%s\">";
        String imgUrl = resourceId;
        if (imageSaveType == 2) {
            //写入HTTP:
            imgUrl = getPictureUrl(resourceId);
        }

        return String.format(formatTag, imgUrl);
    }

    /**
     * 得到保存本地的图片路径.
     *
     * @param fileName word中的图片名称
     * @return 保存本地的图片路径
     */
    private String getPictureFilePath(String fileName) {
        String fileExt = fileName.substring(fileName.lastIndexOf("."));
        String newName = System.currentTimeMillis() + UUID.randomUUID().toString() + fileExt;

        return CommonFunction.getFileFullPath("images", newName);
    }

    /**
     * 上传图片并且获得资源id.
     *
     * @param data the data
     * @return string
     * @throws Exception the exception
     */
    private String uploadPicture(XWPFPictureData data) throws IOException {
        //获得保存到本地的图片路径
        String fileName = getPictureFilePath(data.getFileName());
        //将文件保存到本地并且得到文件对象
        File saveFile = FileUtils.writeFileDataToLocal(data.getData(), fileName);
        if (saveFile == null) {
            return "";
        }
        //将文件上传到资源服务并且得到资源返回的信息
        String urlString = CommonFunction.uploadFileToResourceService(resourceApiUrl, appkey, appSecret, saveFile, ResourceFileType.PICTURE);
        //格式化资源返回信息
        ResourceResponse result = ResourceResponse.init(urlString);

        if (!result.isSuccess()) {
            return "";
        }

        Map<String, String> payload = (Map<String, String>) result.getPayload();
        //返回资源id
        return payload.get("resourceId");
    }

    //endregion

    //region根据resourceId获取url

    /**
     * 根据resourceId获取url
     *
     * @param resourceId resourceId
     * @return
     */

    private String getPictureUrl(String resourceId) throws IOException {
        return CommonFunction.getPathByResources(resourceApiUrl, appkey, appSecret, resourceId, ResourceFileType.PICTURE);
    }
    //endregion

    //region 保留换行替换成为[br]

    /**
     * 保留换行替换成为[br].
     *
     * @param str the str
     * @return the string
     */
    private String convertNewLineString(String str) {
        return str.replace("\n", "[br]").trim();
    }
    //endregion

    //region 去掉全角和半角换行

    /**
     * 去掉全角和半角换行.
     *
     * @param str the str
     * @return the string
     */
    private String removeNewLine(String str) {
        return str.trim().replaceAll("\\u00A0", "").replaceAll("\\n", "");
    }
    private static String htmlText = "";
    private static String htmlTextTbl = "";
    private static int counter = 0;
    private static int beginPosi = 0;
    private static int endPosi = 0;
    private static int beginArray[];
    private static int endArray[];
    private static String htmlTextArray[];
    private static boolean tblExist = false;

    /**
     * 项目路径
     */
    private static String projectRealPath = "";

    /**
     * word文档名称
     */
    private static String wordName = "";

    /**
     * 读取每个文字样式
     *
     * @param fileName
     * @throws Exception
     */

    private String getDataStr(String fileName) throws Exception {
        FileInputStream in = new FileInputStream(new File(fileName));
        HWPFDocument doc = new HWPFDocument(in);

        Range rangeTbl = doc.getRange();// 得到文档的读取范围
        TableIterator it = new TableIterator(rangeTbl);

        int num = 100;
        beginArray = new int[num];
        endArray = new int[num];
        htmlTextArray = new String[num];
        tblExist = false;

        // 取得文档中字符的总数
        int length = doc.characterLength();
        // 创建图片容器
        PicturesTable pTable = doc.getPicturesTable();
        // 创建段落容器
        htmlText = "";
        // 创建临时字符串,好加以判断一串字符是否存在相同格式

        if (it.hasNext()) {
            readTable(it);
        }

        int cur = 0;
        String tempString = "";
        for (int i = 0; i < length - 1; i++) {
            // 整篇文章的字符通过一个个字符的来判断,range为得到文档的范围
            Range range = new Range(i, i + 1, doc);
            CharacterRun cr = range.getCharacterRun(0);
            if (tblExist) {
                if (i == beginArray[cur]) {
                    htmlText += tempString + htmlTextArray[cur];
                    tempString = "";
                    i = endArray[cur] - 1;
                    cur++;
                    continue;
                }
            }
            if (pTable.hasPicture(cr)) {
                htmlText += tempString;
                // 读写图片
                try {
                    readPicture(pTable, cr);
                } catch (Exception e) {
                    logger.error(e);
                }
                tempString = "";
            } else {

                Range range2 = new Range(i + 1, i + 2, doc);
                // 第二个字符
                CharacterRun cr2 = range2.getCharacterRun(0);
                // 比较前后2个字符是否具有相同的格式
                boolean flag = compareCharStyle(cr, cr2);
                if (flag) {
                    tempString += cr.text();
                } else {
                    htmlText += tempString + cr.text();
                    tempString = "";
                }
            }
        }
        htmlText += tempString ;
        return htmlText;
    }

    /**
     * 读写文档中的表格
     *
     * @param it
     * @throws Exception
     */
    private static void readTable(TableIterator it){
        htmlTextTbl = "";
        // 迭代文档中的表格
        counter = -1;
        while (it.hasNext()) {
            tblExist = true;
            htmlTextTbl = "";
            Table tb = (Table) it.next();
            beginPosi = tb.getStartOffset();
            endPosi = tb.getEndOffset();

            counter = counter + 1;
            // 迭代行，默认从0开始
            beginArray[counter] = beginPosi;
            endArray[counter] = endPosi;

            htmlTextTbl += "<table border='1' cellpadding='0' cellspacing='0' >";
            for (int i = 0; i < tb.numRows(); i++) {
                TableRow tr = tb.getRow(i);

                htmlTextTbl += "<tr align='center'>";
                // 迭代列，默认从0开始
                for (int j = 0; j < tr.numCells(); j++) {
                    TableCell td = tr.getCell(j);// 取得单元格
                    int cellWidth = td.getWidth();

                    // 取得单元格的内容
                    for (int k = 0; k < td.numParagraphs(); k++) {
                        Paragraph para = td.getParagraph(k);
                        CharacterRun crTemp = para.getCharacterRun(0);
                        String fontStyle = "<span style=\"font-family:" + crTemp.getFontName() + ";font-size:" + crTemp.getFontSize() / 2 + "pt;color:" + crTemp.getColor() + ";";

                        if (crTemp.isBold())
                            fontStyle += "font- weight:bold;";
                        if (crTemp.isItalic())
                            fontStyle += "font- style:italic;";

                        String s = fontStyle + "\">" + para.text().trim() + "</span>";
                        if (s == "") {
                            s = " ";
                        }
                        htmlTextTbl += "<td width=" + cellWidth + ">" + s + "</td>";
                    }
                }
            }
            htmlTextTbl += "</table>";
            htmlTextArray[counter] = htmlTextTbl;

        } // end while
    }

    /**
     * 读写文档中的图片
     *
     * @param pTable
     * @param cr
     * @throws Exception
     */
    private void readPicture(PicturesTable pTable, CharacterRun cr) throws Exception {
        // 提取图片
        Picture pic = pTable.extractPicture(cr, false);
        BufferedImage image = null;// 图片对象

        // 返回POI建议的图片文件名
        String aFileName = pic.suggestFullFileName();
        //单元测试路径
        String directory = "images/" + wordName + "/";
        //项目路径
        int picSize = cr.getFontSize();
        int myHeight = 0;

        if (aFileName.indexOf(".wmf") > 0) {
            OutputStream out = null;
            try {
                out = new FileOutputStream(new File(projectRealPath + directory + aFileName));
                if(out!=null) {
                    out.write(pic.getContent());
                    File file = new File(projectRealPath + directory + aFileName);
                    if (file != null) {
                        image = ImageIO.read(file);
                    }
                }
            } catch (Exception e) {
                logger.error(e);
            } finally {
                if(out!=null) {
                    out.close();
                }
            }
            if(image != null) {
                if (image.getWidth() > 500) {
                    htmlText += "<img style='width:" + image.getWidth() + "px;height:" + myHeight + "px'" + " src=\"" + directory + aFileName + "\"/>";
                } else {
                    myHeight = (int) (image.getHeight() / (image.getWidth() / (picSize * 1.0)) * 1.5);
                    htmlText += "<img style='vertical- align:middle;width:" + picSize * 1.5 + "px;height:" + myHeight + "px'" + " src=\"" + directory + aFileName + "\"/>";
                }
            }

        } else {
            htmlText += getPitureData(uploadPictureByDoc(pic));
        }
    }

    /**
     * 读取doc中图片上传资源服务 返回资源id
     * @param data
     * @return
     * @throws IOException
     */
    private String uploadPictureByDoc(Picture data) throws IOException {
        //获得保存到本地的图片路径
        String fileName = getPictureFilePath(data.suggestFullFileName());
        //将文件保存到本地并且得到文件对象
        File saveFile = FileUtils.writeFileDataToLocal(data.getContent(), fileName);
        if (saveFile == null) {
            return "";
        }
        //将文件上传到资源服务并且得到资源返回的信息
        String urlString = CommonFunction.uploadFileToResourceService(resourceApiUrl, appkey, appSecret, saveFile, ResourceFileType.PICTURE);
        //格式化资源返回信息
        ResourceResponse result = ResourceResponse.init(urlString);

        if (!result.isSuccess()) {
            return "";
        }

        Map<String, String> payload = (Map<String, String>) result.getPayload();
        //返回资源id
        return payload.get("resourceId");
    }

    private static boolean compareCharStyle(CharacterRun cr1, CharacterRun cr2) {
        boolean flag = false;
        if (cr1.isBold() == cr2.isBold() && cr1.isItalic() == cr2.isItalic()
                && cr1.getFontName().equals(cr2.getFontName())

                && cr1.getFontSize() == cr2.getFontSize()) {
            flag = true;
        }
        return flag;
    }
}
